import { pause } from 'wot-design-uni/components/common/util'
import { useDeviceStore } from '@/stores/'
import protosAdapter from '@/utils/protos/index.js'
// 使用闭包实现私有构造函数 -- 单例模式 https://blog.csdn.net/weixin_45955709/article/details/140707961
// const DeviceClass = (function () {
//   let instance = null
//   class Device {
//     constructor() {
//       if (instance) {
//         return instance
//       }
//       // 初始化蓝牙相关的状态或变量
//       // this.optsNotify = [] //用于防止重复启动notify功能
//       this.optsNotify = null //用于防止重复启动notify功能
//       uni.onBLECharacteristicValueChange((res) => {
//         // console.log('listenNotify Change：', res)
//         if (!this.optsNotify) return
//         if (
//           this.optsNotify.deviceId === res.deviceId &&
//           this.optsNotify.serviceId === res.serviceId &&
//           this.optsNotify.characteristicId === res.characteristicId
//         ) {
//           const resData = this.ab2hex(res.value)
//           // console.log('listenNotify resData', resData)
//           uni.$emit(uni.$myNotifyEventName, resData)
//         }
//       })
//       instance = this
//     }
//     // 静态方法，用于获取蓝牙管理器的实例
//     static getInstance() {
//       if (!instance) {
//         instance = new Device()
//       }
//       return instance
//     }

//     // ArrayBuffer转16进度字符串示例
//     ab2hex(buffer) {
//       var hexArr = Array.prototype.map.call(new Uint8Array(buffer), function (bit) {
//         return ('00' + bit.toString(16)).slice(-2)
//       })
//       // console.log('ab2hex: ', hexArr)
//       return hexArr
//     }

//     // 启用 notify 功能
//     listenNotify(opt) {
//       return new Promise((resolve, reject) => {
//         // 预防重复启动
//         // const isNotify = this.optsNotify.some((item) => JSON.stringify(item) == JSON.stringify(opt))
//         uni.notifyBLECharacteristicValueChange({
//           state: true, // 启用 notify 功能
//           ...opt,
//           success: (message) => {
//             console.log('成功启用 notify 功能', opt)
//             // this.optsNotify.push(opt)
//             this.optsNotify = opt
//             console.log('listenNotify：', message)
//             resolve()
//           },
//           fail: (e) => {
//             console.log('listen err', e)
//             errorHandler(e)
//             reject(e)
//           },
//         })
//       })
//     }
//   }
//   return Device
// })()
// const deviceClass = new DeviceClass()

// 错误信息
export const bluetoothErrMsg = new Map([
  ['0', { errMsg: 'ok', message: '正常' }],
  ['-1', { errMsg: 'already connect', message: '已连接' }],
  ['10000', { errMsg: 'not init', message: '未初始化蓝牙适配器' }],
  ['10001', { errMsg: 'not available', message: '当前蓝牙适配器不可用' }],
  ['10002', { errMsg: 'no device', message: '没有找到指定设备' }],
  ['10003', { errMsg: 'connection fail', message: '连接失败' }],
  ['10004', { errMsg: 'no service', message: '没有找到指定服务' }],
  ['10005', { errMsg: 'no characteristic', message: '没有找到指定特征值' }],
  ['10006', { errMsg: 'no connection', message: '当前连接已断开' }],
  ['10007', { errMsg: 'property not support', message: '当前特征值不支持此操作' }],
  ['10008', { errMsg: 'system error', message: '其余所有系统上报的异常' }],
  [
    '10009',
    { errMsg: 'system not support	Android', message: '系统特有，系统版本低于 4.3 不支持 BLE' },
  ],
  ['10010', { errMsg: 'already connect', message: '已连接' }],
  ['10011', { errMsg: 'need pin', message: '配对设备需要配对码' }],
  ['10012', { errMsg: 'operate time out', message: '连接超时' }],
  ['10013', { errMsg: 'invalid_data', message: '连接 deviceId 为空或者是格式不正确' }],
])
/**
 * "deviceId": "A2:22:03:29:01:E4",
   "name": "BEM4",
   "advertisServiceUUIDs": [
      "5855414E-0000-1000-8000-00805F9B34FB"
    ]
 * "deviceId": "B0:78:39:8B:FE:37",
   "name": "XHXL-FE36",
   "advertisServiceUUIDs": [
    ]
 */

// 节流
// function throttle(fn, t = 1000) {
//   let timer = null
//   return function (...args) {
//     if (timer) return
//     timer = setTimeout(() => {
//       fn.apply(this, args)
//       timer = null
//     }, t)
//   }
// }

/**
 * 错误处理
 * @param {Object} err 错误信息
 * @param {String} err.errMsg 错误信息
 * @param {String} err.code 错误码
 */
async function errorHandler(err) {
  // uni.showToast({
  //   title: bluetoothErrMsg.get(err.code?.toString())?.message || '未知错误',
  //   icon: 'none',
  // })
  await uni.$globalMessage.alert({
    msg: bluetoothErrMsg.get(err.code?.toString())?.message || '未知错误',
    title: '提示',
    confirmButtonText: '确认',
  })
  if (['10000', '10001'].includes(err.code)) {
    await initBlueTooth()
  }
}
/**
 * 打开蓝牙
 */
function openBlueTooth() {
  let main, Context, BManager, BAdapter
  main = plus.android.runtimeMainActivity()
  Context = plus.android.importClass('android.content.Context')
  BManager = main.getSystemService(Context.BLUETOOTH_SERVICE)
  plus.android.importClass(BManager) //引入相关的method函数
  BAdapter = BManager.getAdapter()
  plus.android.importClass(BAdapter) //引入相关的method函数，这样之后才会有isEnabled函数支持
  if (!BAdapter.isEnabled()) {
    BAdapter.enable()
    console.log('打开蓝牙')
  }
}

/**
 * 打开蓝牙适配器
 */
async function initBlueTooth() {
  return new Promise((resolve, reject) => {
    // 打开蓝牙适配
    uni.openBluetoothAdapter({
      async success() {
        // 获取本机蓝牙适配器状态。
        const status = await uni.getBluetoothAdapterState()
        console.log('3 蓝牙适配器是否可用', status.available)
        if (!status.available) {
          uni.$globalMessage.alert({
            msg: '蓝牙适配器不可用',
            title: '提示',
            confirmButtonText: '好的',
          })
          reject()
          return
        }
        resolve()
      },
      async fail(err) {
        if (err.errMsg === 'openBluetoothAdapter:fail already opened') {
          uni.showToast({
            icon: 'none',
            title: '蓝牙已打开',
          })
        }
        if ([10001].includes(err.code)) {
          console.log('蓝牙适配失败！原因：微信未给用户授权；或者系统未给微信授权', err)
          await uni.$globalMessage.alert({
            msg: '请确认手机蓝牙是否打开',
            title: '提示',
            confirmButtonText: '好的',
          })
          try {
            openBlueTooth()
          } catch (error) {
            console.log('openBlueTooth error:', error)
          }
        }
        reject(new Error('请确认手机蓝牙是否打开'))
      },
    })
  })
}

/**
 * 扫描蓝牙设备
 * @returns {Array} 扫描到的蓝牙设备
 */
async function scanBlueTooth() {
  // 初始化蓝牙
  await initBlueTooth()

  // 搜索设备
  await uni.startBluetoothDevicesDiscovery()
  // uni.showLoading({
  //   mask: true,
  //   title: '设备扫描中',
  // })
  return new Promise((resolve, reject) => {
    let timer
    clearTimeout(timer)
    timer = setTimeout(async () => {
      // 停止搜索
      uni.stopBluetoothDevicesDiscovery()
      // uni.hideLoading()
      // 获取已搜索到的蓝牙设备
      const devices = await uni.getBluetoothDevices()
      // 筛选蓝牙设备
      const filterRes = devices.devices.filter(
        (v) => v.name.startsWith('BEM') || v.name.startsWith('XHXL'),
      )
      console.log('filterRes:', filterRes)
      // 没找到，进行提示
      if (filterRes.length == 0) {
        uni.$globalMessage.alert({
          msg: '没有找到附近的设备，请确认扳手是否开机。如果扳手已经开机，请点击【搜索设备】按钮重新扫描',
          title: '提示',
        })
        // uni.showModal({
        //   title: '提示',
        //   content:
        //     '没有找到附近的设备，请确认扳手是否开机。如果扳手已经开机，请点击【搜索设备】按钮重新扫描',
        //   showCancel: false,
        // })
        reject(new Error('没有找到附近的设备'))
        return
      }
      // 添加设备
      const deviceStore = useDeviceStore()
      deviceStore.addDevice(filterRes)
      resolve(filterRes)
    }, 3000)
  })
}

/**
 * 连接设备
 * @param {Object} device 设备信息
 * @param {String} device.deviceId 设备id
 * @param {String} device.name 设备名称
 * @param {String} device.rssi 设备信号强度
 * @param {String} device.advertisData 设备广播数据
 * @param {String} device.advertisServiceUUIDs 设备服务UUID
 */
async function connectDevice(device) {
  // 打开蓝牙适配器
  await initBlueTooth()
  return new Promise((resolve, reject) => {
    uni.showLoading({ title: '连接中', mask: true })
    let { deviceId } = device
    // 连接蓝牙
    uni.createBLEConnection({
      deviceId,
      timeout: 10000,
      success: async function () {
        // 设置最大传输单元127
        await pause(500)
        await setBLEMTU(deviceId, 127)
        // 获取蓝牙特征
        const opts = await getCharacteristicId(deviceId)
        // 保存蓝牙设备和特征值
        const deviceStore = useDeviceStore()
        deviceStore.setCurDevice(device)
        deviceStore.setCurDeviceItem('opts', opts)
        // 适配协议
        protosAdapter()
        // 订阅特征值
        await listenNotify(opts.notify)
        // await deviceClass.listenNotify(opts.notify)
        uni.hideLoading()
        uni.showToast({ title: '连接成功', icon: 'success' })
        resolve()
      },
      fail: function (error) {
        uni.hideLoading()
        console.log('createBLEConnection error', error)
        // uni.showToast({ title: '连接失败',icon: 'error' })
        errorHandler(error)
        reject()
      },
      complete: async function () {
        // uni.hideLoading()
        await uni.stopBluetoothDevicesDiscovery()
      },
    })
  })
}

/**
 * 获取蓝牙特征
 * @param {String} deviceId 设备ID
 * @returns {Object} opts 蓝牙特征
 * {
      write: {
        characteristicId: '0000FFF2-0000-1000-8000-00805F9B34FB',
        deviceId: 'B0:78:39:8B:FE:37',
        serviceId: '0000FFF0-0000-1000-8000-00805F9B34FB',
      },
      notify: {
        characteristicId: '0000FFF1-0000-1000-8000-00805F9B34FB',
        deviceId: 'B0:78:39:8B:FE:37',
        serviceId: '0000FFF0-0000-1000-8000-00805F9B34FB',
      },
    }
 */
// 延时获取，https://ask.dcloud.net.cn/question/115249
// function getCharacteristicId(deviceId) {
//   return new Promise((resolve, reject) => {
//     uni.showLoading({ title: '获取特征中...' })
//     let time = 3
//     const opts = {}
//     async function get() {
//       time--
//       // 获取蓝牙设备的所有服务
//       const { services /* , errMsg */ } = await uni.getBLEDeviceServices({ deviceId })
//       console.log('6 蓝牙特征服务ID', services)
//       if (services.length <= 0) {
//         if (time < 0) {
//           uni.showToast({ title: '未找到读写特征值', icon: 'none' })
//           reject('未找到读写特征值')
//           return
//         }
//         setTimeout(get, 1000)
//         return
//       }
//       for (let i = 0; i < services.length; i++) {
//         const serviceId = services[i].uuid
//         // 获取蓝牙设备指定服务中所有特征值
//         let characteristics = await uni.getBLEDeviceCharacteristics({ deviceId, serviceId })
//         // console.log('7 蓝牙特征', characteristics.characteristics)
//         if (!opts.write) {
//           // 找有写权限的特征ID
//           let canWrite = characteristics.characteristics.find((v) => v.properties.write == true)
//           if (canWrite) {
//             opts.write = {
//               characteristicId: canWrite.uuid,
//               deviceId,
//               serviceId,
//             }
//             // console.log('8 找到有写入权限的特征', canWrite)
//           }
//         }

//         if (!opts.notify) {
//           // 找有notify 权限的特征ID
//           let canNotify = characteristics.characteristics.find((v) => v.properties.notify == true)
//           if (canNotify) {
//             opts.notify = {
//               characteristicId: canNotify.uuid,
//               deviceId,
//               serviceId,
//             }
//             // console.log('9 找到有 读 和 notify 权限的特征', canNotify)
//           }
//         }
//         if (opts.write && opts.notify) break
//       }

//       console.log('opts', opts)
//       uni.hideLoading()
//       resolve(opts)
//       return
//     }
//     setTimeout(get, 1000)
//   })
// }
function getCharacteristicId(deviceId) {
  return new Promise((resolve, reject) => {
    uni.showLoading({ title: '获取特征中...' })
    let time = 3
    async function get() {
      time--
      // 获取蓝牙设备的所有服务
      const { services /* , errMsg */ } = await uni.getBLEDeviceServices({ deviceId })
      console.log('6 蓝牙特征服务ID', services)
      if (services.length <= 0) {
        if (time < 0) {
          uni.showToast({ title: '未找到读写特征值', icon: 'none' })
          reject('未找到读写特征值')
          return
        }
        setTimeout(get, 1000)
        return
      }
      const opts = {
        write: {
          characteristicId: '0000FFF2-0000-1000-8000-00805F9B34FB',
          deviceId,
          serviceId: '0000FFF0-0000-1000-8000-00805F9B34FB',
        },
        notify: {
          characteristicId: '0000FFF1-0000-1000-8000-00805F9B34FB',
          deviceId,
          serviceId: '0000FFF0-0000-1000-8000-00805F9B34FB',
        },
      }

      console.log('opts', opts)
      // uni.hideLoading()
      resolve(opts)
      return
    }
    setTimeout(get, 1000)
  })
}

/**
 * 发送至设备
 * @param {Object} opt 设备特征值 写
 * @param {String[]} value 指令数组 --不包含校验码
 * @param {Function} callback 回调函数
 */
function sendToDevice(opt = {}, value, callback) {
  return new Promise((resolve, reject) => {
    // console.log('send', opt, value)
    // let value = uni.$utils.cmd.getSendData();
    uni.writeBLECharacteristicValue({
      ...opt,
      value,
      success(res) {
        console.log('success  指令发送成功', value)
        callback && callback()
        resolve(res)
      },
      fail: function (res) {
        console.log('fail: writeBLECharacteristicValue fail', res)
        errorHandler(res)
        reject()
      },
      resolve,
    })
  })
}

/**
 * 订阅特征值
 * @param {Object} opt 特征值 notify为true
 * @param {String} opt.characteristicId 特征值ID
 * @param {String} opt.deviceId 设备ID
 * @param {String} opt.serviceId 服务ID
 * @returns
 */
function listenNotify(opt) {
  return new Promise((resolve, reject) => {
    uni.notifyBLECharacteristicValueChange({
      ...opt,
      state: true,
      success(message) {
        console.log('listenNotify：', message)
        resolve(message)
      },
      fail(e) {
        console.log('listen err', e)
        errorHandler(e)
        reject(e)
      },
    })
  })
}

/**
 * 设置蓝牙最大传输单元
 * @param {String} deviceId 设备ID
 * @param {Number} mtu 最大传输单元 - 范围(22,512)
 * @returns
 */
function setBLEMTU(deviceId, mtu) {
  return new Promise((resolve, reject) => {
    uni.setBLEMTU({
      deviceId,
      mtu,
      success: (success) => {
        console.log('设置蓝牙最大传输单元', success)
        resolve()
      },
      fail(e) {
        console.log('设置蓝牙最大传输单元失败', e)
        uni.showToast({ title: '设置蓝牙最大传输单元失败', icon: 'fail' })
        reject(e)
      },
    })
  })
}
/**
 * 断开蓝牙连接
 * @param {String} deviceId 设备ID
 */
function disconnectDevice(device) {
  uni.closeBLEConnection({
    deviceId: device.deviceId,
    success: () => {
      uni.$off(uni.$myNotifyEventName)
      uni.showToast({ title: device.name + '断开', icon: 'none' })
    },
  })
}
export default {
  openBlueTooth,
  initBlueTooth,
  scanBlueTooth,
  connectDevice,
  getCharacteristicId,
  sendToDevice,
  // listenNotify,
  setBLEMTU,
  disconnectDevice,
}
